/*
 * Copyright (C) 2025 ameise <ameise.wang@gmail.com> - All Rights Reserved
 *
 * This file is part of e3pool.
 *
 * e3pool is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * e3pool is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with e3pool. If not, see <https://www.gnu.org/licenses/>.
 */

package go_pool

import (
	"context"
	"sync"
)

func newSimRunner(h PanicHook, where string) *runnerSim {
	r := &runnerSim{
		panicHook: h,
		where:     where,
	}
	return r
}

type runnerSim struct {
	opts      Options
	panicHook PanicHook
	where     string
	wg        sync.WaitGroup
}

func (ts *runnerSim) SyncRun(f GoSyncFunc, args ...any) (any, error) {
	ch := make(chan taskResult)
	t := newTask(ch, f, args)
	defer freeTask(t)
	if err := ts.post(t); err != nil {
		return nil, err
	}
	rs := <-ch
	return rs.result, rs.err
}

func (ts *runnerSim) AsyncRun(f GoAsyncFunc, args ...any) error {
	t := newTask(nil, f, args)
	if err := ts.post(t); err != nil {
		freeTask(t)
		return err
	}
	return nil
}

func (ts *runnerSim) Wait() {
	ts.wg.Wait()
}

func (ts *runnerSim) post(t *task) (err error) {
	if ts.opts.limiter != nil {
		ctx := context.Background()
		if ts.opts.isBlock {
			if err = ts.opts.limiter.Wait(ctx); err != nil {
				return ErrRunnerPostTimeOut
			}
		} else {
			if !ts.opts.limiter.Allow() {
				return ErrRunnerLimit
			}
		}
	}
	ts.wg.Add(1)
	goWorkerDo(ts.consume, t)
	return nil
}

func (ts *runnerSim) consume(args ...any) {
	t := args[0].(*task)
	doTaskSafe(ts.panicHook, ts.where, t)
	ts.wg.Done()
}
